const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const {
  userFormateError,
  userAlreadyExited,
  validatorUser,
  verifyUsername,
  psdError,
  tokenError,
  tokenPastDue,
  noAdminPer,
} = require("../constant/err.type");
const { getUserInfo } = require("../service/user.service");
const userValidator = async (ctx, next) => {
  const { username, password } = ctx.request.body;
  if (!username || !password) {
    ctx.app.emit("error", userFormateError, ctx);
    return;
  }
  await next();
};
const verifyUser = async (ctx, next) => {
  const { username } = ctx.request.body;
  if (await getUserInfo({ username })) {
    ctx.status = 409;
    ctx.app.emit("error", userAlreadyExited, ctx);
    return;
  }
  await next();
};
const cryptPsd = async (ctx, next) => {
  const { password } = ctx.request.body;
  const salt = bcrypt.genSaltSync(10);

  //hash 保存的是密文
  const hash = bcrypt.hashSync(password, salt);
  ctx.request.body.password = hash;
  await next();
};
const validatorUserIpt = async (ctx, next) => {
  const { username, password } = ctx.request.body;
  if (!username || !password) {
    ctx.app.emit("error", validatorUser, ctx);
    return;
  }
  await next();
};
const verifyUserIpt = async (ctx, next) => {
  const { username, password } = ctx.request.body;
  let res = await getUserInfo({ username });
  if (!res) {
    ctx.app.emit("error", verifyUsername, ctx);
    return;
  } else if (res) {
    let psd = res.password;
    if (bcrypt.compareSync(password, psd)) {
      await next();
    } else {
      ctx.app.emit("error", psdError, ctx);
      return;
    }
  }
};
const verifyToken = async (ctx, next) => {
  try {
    let token = ctx.headers.token;
    let res = jwt.verify(token, process.env.JWT_SECRET);
    ctx.state.user = res.dataValues;
  } catch (err) {
    switch (err.name) {
      case "JsonWebTokenError":
        ctx.app.emit("error", tokenError, ctx);
        return;
      case "TokenExpiredError":
        ctx.app.emit("error", tokenPastDue, ctx);
        return;
    }
  }
  await next();
};
const hasAdminPer = async (ctx, next) => {
  const res = ctx.state.user;
  if (res.is_admin) {
    await next();
  } else {
    ctx.app.emit("error", noAdminPer, ctx);
    return;
  }
};
module.exports = {
  userValidator,
  verifyUser,
  cryptPsd,
  validatorUserIpt,
  verifyUserIpt,
  verifyToken,
  hasAdminPer,
};
